package com.qf.business.student.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ken.event.action.apply.producer.EventTemplate;
import com.qf.business.classes.feign.ClsFeign;
import com.qf.business.student.dao.StudentDao;
import com.qf.business.student.service.StudentService;
import com.qf.commons.redis.annotation.RLocks;
import com.qf.data.student.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;

/**
 * 学生表(Student)表服务实现类
 *
 * @author makejava
 * @since 2022-11-12 17:00:12
 */
@Service("studentService")
public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> implements StudentService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ClsFeign clsFeign;

    /**
     * 下单的请求
     *
     * local key = KEYS[1]
     * local timeout = ARGV[1]
     * local result = redis.call('setnx', key, '1')
     * if result == 1 then
     *     --说明加锁成功
     *     redis.call('expire', key, timeout)
     *     return 1
     * else
     *     return 0
     * end
     *
     * @return

    public int createOrder(Integer gid, Integer uid, Integer number){
        //下单的请求
        //添加分布式锁
        while(true) {
            Boolean bool = redisTemplate.opsForValue().setIfAbsent("mylock::orders::" + gid, "1", 30, TimeUnit.SECONDS);
            if (bool) {
                System.out.println("获得分布式锁！");
                //核心下单的业务
                //核心业务执行完成 需要手动释放锁
                redisTemplate.delete("mylock::orders::" + gid);
                return 1;
            }
        }
    }*/

    /*
    aop -> 任何业务都可以拆分成 【核心业务】 【非核心业务】 而每个业务的核心业务必然是不同的，但是非核心业务却有很多相同的部分，
       将这些非核心业务代码抽取出来形成一个个的切面，针对这些切面进行相应的编程，运行时通过织入的方式再将非核心业务与核心业务组装成一个完成的业务。
       这种编程方式就称之为面向切面编程
     */
    @Override
//    @Cacheable(cacheNames = "mycache", key = "'stulist'")
    public List<Student> list() {
        System.out.println("查询学生列表！");
        //feign 同步调用 班级服务的接口
        String clsInfo = clsFeign.query(18);
        System.out.println("获得班级信息：" + clsInfo);

        return super.list();
    }

    @Override
    @CacheEvict(cacheNames = "mycache", key = "'stulist'")
    @Transactional
    @RLocks(key = "'mylock_' + #entity.name")
    public boolean save(Student entity) {

        //发布一个自定义的事件消息
        EventTemplate.sendQuickly("stu_insert", entity);

        //通过kafka 通知给 班级服务
        return super.save(entity);
    }

    @Override
    @Cacheable(cacheNames = "mycache", key = "'stu' + #id")
    public Student getById(Serializable id) {
        return super.getById(id);
    }
}

